package cn.enilu.flash.service;

import cn.enilu.flash.bean.constant.CfgKey;
import cn.enilu.flash.bean.entity.shop.Order;
import cn.enilu.flash.bean.entity.shop.OrderItem;
import cn.enilu.flash.bean.entity.shop.Refund;
import cn.enilu.flash.bean.entity.shop.ShopUser;
import cn.enilu.flash.bean.enumeration.shop.OrderEnum;
import cn.enilu.flash.bean.vo.query.SearchFilter;
import cn.enilu.flash.service.shop.OrderItemService;
import cn.enilu.flash.service.shop.OrderService;
import cn.enilu.flash.service.shop.RefundService;
import cn.enilu.flash.service.system.CfgService;
import cn.enilu.flash.utils.HttpUtil;
import cn.enilu.flash.utils.Lists;
import cn.enilu.flash.utils.StringUtil;
import com.github.binarywang.wxpay.bean.notify.WxPayNotifyResponse;
import com.github.binarywang.wxpay.bean.notify.WxPayOrderNotifyResult;
import com.github.binarywang.wxpay.bean.notify.WxPayRefundNotifyResult;
import com.github.binarywang.wxpay.bean.order.WxPayMpOrderResult;
import com.github.binarywang.wxpay.bean.request.WxPayUnifiedOrderRequest;
import com.github.binarywang.wxpay.constant.WxPayConstants;
import com.github.binarywang.wxpay.exception.WxPayException;
import com.github.binarywang.wxpay.service.WxPayService;
import org.apache.commons.io.IOUtils;
import org.nutz.json.Json;
import org.nutz.lang.random.R;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.math.BigDecimal;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * 微信支付
 * @author ：enilu
 * @date ：Created in 2020/3/17 20:26
 */
@Service
public class WeixinPayService {
    @Autowired
    private WxPayService wxPayService;
    @Autowired
    private OrderService orderService;
    @Autowired
    private CfgService cfgService;
    @Autowired
    private OrderItemService orderItemService;
    @Autowired
    private RefundService refundService;
    private Logger logger = LoggerFactory.getLogger(WeixinPayService.class);
    public WxPayMpOrderResult prepare(ShopUser user, Order order){

        WxPayUnifiedOrderRequest orderRequest = new WxPayUnifiedOrderRequest();
        orderRequest.setOutTradeNo(order.getOrderSn());
        orderRequest.setOpenid(user.getWechatOpenId());
        orderRequest.setBody("订单：" + order.getOrderSn());
        BigDecimal totalPrice = order.getTotalPrice();
        orderRequest.setTotalFee(totalPrice.intValue());
        orderRequest.setSpbillCreateIp(HttpUtil.getIp());
        //小程序支付
        orderRequest.setTradeType(WxPayConstants.TradeType.JSAPI);
        orderRequest.setNotifyUrl(cfgService.getCfgValue(CfgKey.WX_NOTIFY));
        try {
            WxPayMpOrderResult result = wxPayService.createOrder(orderRequest);
            orderService.startPay(order);
            return  result;
        } catch (WxPayException e) {
            logger.error("微信支付异常",e);

        }
        return null;
    }

    @Transactional
    public String resultNotify() {
        String xmlResult = null;

        try {
            HttpServletRequest request = HttpUtil.getRequest();
            xmlResult = IOUtils.toString(request.getInputStream(), request.getCharacterEncoding());

        } catch (IOException e) {
            logger.error("解析微信支付结果通知异常",e);
            return WxPayNotifyResponse.fail(e.getMessage());
        }

        WxPayOrderNotifyResult result = null;
        try {
            result = wxPayService.parseOrderNotifyResult(xmlResult);

            if(!WxPayConstants.ResultCode.SUCCESS.equals(result.getResultCode())){
                logger.error(xmlResult);
                throw new WxPayException("微信通知支付失败！");
            }
            if(!WxPayConstants.ResultCode.SUCCESS.equals(result.getReturnCode())){
                logger.error(xmlResult);
                throw new WxPayException("微信通知支付失败！");
            }
        } catch (WxPayException e) {
            e.printStackTrace();
            return WxPayNotifyResponse.fail(e.getMessage());
        }

        logger.info("处理腾讯支付平台的订单支付", Json.toJson(result));

        String orderSn = result.getOutTradeNo();
        String payId = result.getTransactionId();

        Integer totalFee =  result.getTotalFee();
        Order order = orderService.getByOrderSn(orderSn);
        if (order == null) {
            return WxPayNotifyResponse.fail("订单不存在 sn=" + orderSn);
        }

        // 检查这个订单是否已经处理过
        if (order.hasPayed()) {
            return WxPayNotifyResponse.success("订单已经处理成功!");
        }

        // 检查支付订单金额
        if (totalFee.intValue()!=order.getTotalPrice().intValue()) {
            return WxPayNotifyResponse.fail(order.getOrderSn() + " : 支付金额不符合 totalFee=" + totalFee);
        }

        order.setPayId(payId);
        orderService.paySuccess(order, OrderEnum.PayTypeEnum.UN_SEND.getKey());

        //刷新订单详情表支付状态
        List<OrderItem> orderItemList = orderItemService.queryAll(SearchFilter.build("idOrder",order.getId()));
        orderItemList.forEach(l->{
            l.setPayStatus(1);
            orderItemService.update(l);
        });
        splitOrder(orderItemList,order);
        return WxPayNotifyResponse.success("支付成功！");
    }

    public void splitOrder(List<OrderItem> orderItemList,Order order){
        //拆单
        Map<Long,List<OrderItem>> orderItemMap = orderItemList.stream().collect(Collectors.groupingBy(OrderItem::getGoodsCreat));
        if(orderItemMap.keySet().size() > 1){
            orderItemMap.forEach((key,value)->{
                Order newOrder = new Order();
                BeanUtils.copyProperties(order,newOrder);
                newOrder.setOrderSn(newOrder.getOrderSn()+"-"+key.toString());
                BigDecimal price = value.stream().map(OrderItem::getTotalPrice).reduce(BigDecimal.ZERO,BigDecimal::add);
                newOrder.setRealPrice(price);
                newOrder.setId(null);
                newOrder.setItems(null);
                newOrder.setGoodsCreat(key);
                orderService.insert(newOrder);
                orderItemMap.get(key).forEach(l->{
                    l.setIdOrder(newOrder.getId());
                    orderItemService.update(l);
                });
            });
            order.setItems(null);
            order.setStatus(OrderEnum.OrderStatusEnum.HAS_SPLIT.getId());
            orderService.update(order);
        }else if(orderItemMap.keySet().size() == 1){
            Set<Long> keySet = orderItemMap.keySet();
            for(Long s: keySet){
                order.setGoodsCreat(s);
                orderService.update(order);
            }
        }
    }

    @Transactional
    public String wxRefundNotify() {
        String xmlResult = null;

        try {
            HttpServletRequest request = HttpUtil.getRequest();
            xmlResult = IOUtils.toString(request.getInputStream(), request.getCharacterEncoding());
            logger.info("处理腾讯支付平台的退款订单",xmlResult);
        } catch (IOException e) {
            logger.error("解析微信退款结果通知异常",e);
            return WxPayNotifyResponse.fail(e.getMessage());
        }

        WxPayRefundNotifyResult wxPayRefundNotifyResult = null;
        try {
            wxPayRefundNotifyResult = wxPayService.parseRefundNotifyResult(xmlResult);
            if(!WxPayConstants.ResultCode.SUCCESS.equals(wxPayRefundNotifyResult.getReturnCode())){
                logger.error(xmlResult);
                throw new WxPayException("微信通知退款失败！");
            }
        } catch (WxPayException e) {
            e.printStackTrace();
            return WxPayNotifyResponse.fail(e.getMessage());
        }
        logger.info("处理腾讯支付平台的退款订单", Json.toJson(wxPayRefundNotifyResult.getReqInfo()));
        String orderSn = wxPayRefundNotifyResult.getReqInfo().getOutRefundNo();
        Order order = orderService.getByOrderSn(orderSn);
        order.setStatus(OrderEnum.OrderStatusEnum.REFUND.getId());
        orderService.update(order);
        Refund refund = new Refund();
        refund.setOrderSn(orderSn);
        refund.setMoney(wxPayRefundNotifyResult.getReqInfo().getRefundFee());
        refund.setWxSn(wxPayRefundNotifyResult.getReqInfo().getTransactionId());
        refund.setShSn(wxPayRefundNotifyResult.getReqInfo().getOutTradeNo());
        refund.setTkWxSn(wxPayRefundNotifyResult.getReqInfo().getRefundId());
        refund.setTkShSn(wxPayRefundNotifyResult.getReqInfo().getOutRefundNo());
        refundService.insert(refund);
        return WxPayNotifyResponse.success("退款成功！");
    }
}
